package com.bearingnavi.android.listeners;

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.graphics.Point;
import android.view.View;

import com.bearingnavi.android.BearingNaviActivity;
import com.bearingnavi.android.overlays.BearingOverlay;
import com.bearingnavi.android.services.LocationService;
import com.bearingnavi.android.util.ClickableLineOverlay;
import com.bearingnavi.android.util.ClickableOverlay;
import com.bearingnavi.android.util.Mathematics;
import com.bearingnavi.android.views.LongpressMapView.OnLongpressListener;
import com.bearingnavi.android.views.LongpressPopupPanel;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;

public class MapLongpressHandler implements OnLongpressListener {
	
	private final int PIXEL_DEVIATION = 30;
	private View view;
	private LongpressPopupPanel panel;
	
	public MapLongpressHandler(Context context, View view) {
		this.view = view;
		this.panel = new LongpressPopupPanel((BearingNaviActivity) context, (MapView) view);
	}

	public void onLongpress(final MapView mapView, final GeoPoint geoPoint, final Point point) {
		
		Projection projection = mapView.getProjection();
		Overlay closestOverlay = null;
		int minDeviation = -1;
		boolean hasWP = false;
		synchronized (mapView.getOverlays()) {
			
			
			for (Overlay overlay : mapView.getOverlays()) {
				int pointDeviation = -1;
				
				if (overlay instanceof ClickableOverlay) {
					if (overlay instanceof ClickableLineOverlay) {
						if (!hasWP){						 // Prefer WayPoint over Bearing line
							List<GeoPoint> geoPoints = ((ClickableLineOverlay) overlay).getLinePoints();
							if (geoPoints.size() != 2) {
								continue;
							}
							
							if (pointDeviation == -1) {
								Point pointA = projection.toPixels(geoPoints.get(0), null);
								Point pointB = projection.toPixels(geoPoints.get(1), null);
								pointDeviation = Mathematics.isPointCloseToLine(pointA, pointB, point, PIXEL_DEVIATION);
								if (pointDeviation != -1 && (pointDeviation < minDeviation || minDeviation == -1)) {
									closestOverlay = overlay;
									minDeviation = pointDeviation;
								}
							}
						}
					} else {
						GeoPoint clickableGeoPoint = ((ClickableOverlay)overlay).getClickablePoint();
						
						Point point2 = projection.toPixels(clickableGeoPoint, null);
						
						pointDeviation = Mathematics.isClosePoints(point, point2, PIXEL_DEVIATION);
						if (pointDeviation != -1 && (pointDeviation < minDeviation || minDeviation == -1 || closestOverlay instanceof BearingOverlay)) {
							hasWP = true;
							closestOverlay = overlay;
							minDeviation = pointDeviation;
						}
					}
				}
			}
			
		}
		
		if (minDeviation != -1) {
			final Overlay fOverlay = closestOverlay;
			handleShowTheChosenOverlay(fOverlay, mapView, new Runnable() {
				
				public void run() {
					view.post(new Runnable() {
						
						public void run() {
							panel.show(geoPoint, point, fOverlay);
						}
					});	
				}
			});
		} else {
			//In case no overlay was caught then open new dialog asking the user what to do with this point.
			//Some new dialog with 'longpressLocation' GeoPoint.
			view.post(new Runnable() {
				
				public void run() {
					panel.show(geoPoint, point, null);
				}
			});
		}
	}
	
	private void handleShowTheChosenOverlay(final Overlay overlay, final MapView mapView, final Runnable callback) {
		((ClickableOverlay)overlay).onChosenEvent(mapView);
		mapView.postInvalidate();
		final Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			
			@Override
			public void run() {
				((ClickableOverlay)overlay).onReleaseChosenEvent(mapView);
				mapView.postInvalidate();
				callback.run();
			}
		}, 1000);
	}
	
		
	public void onLongpressStart() {
		LocationService.setHoldMap(true);
	}

	public void onLongpressEnd() {
		LocationService.setHoldMap(false);
	}
	
}
